/**
    @file       2007_V10_C.c
    @date       2013-10-3 22:34
    @author     Yura Gorishniy
    @version    1.01

    @par        The program asks for a natural number and tries to
                decompose it in three squared numbers
                (these numbers are whole and not-negative)

    @note       V 1.01
                - added asserts
                - code style improved
**/


#include <stdio.h>
#include <stdlib.h>
#include <math.h>


//#define DEBUG

#ifdef DEBUG
    #define ASSERT(cond)                                                                        \
    if (!(cond))                                                                                \
    {                                                                                           \
        printf("The state is wrong: %s, file: %s, line: %d\n", #cond, __FILE__, __LINE__);      \
        abort();                                                                                \
    }

#else
    #define ASSERT(cond)
#endif //DEBUG


//#define _EJC

#ifdef  _EJC
    #define OUT if (0)
#else
    #define OUT
#endif // _EJC


/**
    Contains_3_Sqr - tries to find a possibility to decompose
                     natural number in three squared numbers

    @param          num   the number, which the function will try to decompose
                        like a^2 + b^2 + c^2
    @param[out]     sqr1   the first  square
    @param[out]     sqr2   the second square
    @param[out]     sqr3   the third  square

    @return             1 if decomposition exists; saves squares in sqr1, sqr2 and sqr3
                       -1 if decomposition does not exists

    @note               The squared numbers are whole and not-negative
**/

int Contains_3_Sqr (long num, long* sqr1, long* sqr2, long* sqr3);

/**
    main        prints the decomposition, if it exists
                prints -1 if there is no decompositions

    @return     0 if the program finishes successfully
               -1 if input is incorrect
**/

int main ()
{
    long sqr1 = -1, sqr2 = -1, sqr3 = -1;
    long n = 0;

    OUT printf ("# This is a program, which decomposes entered natural number\n"
                "  in three squares of whole not-negative numbers,\n"
                "  if it's possible.\n"
                "# The developer:   Yura Gorishniy    <strausmg@gmail.com>\n"
                "# Version 1.01\n"
                "# The file: %s\n"
                "# The compilation time: %s, %s\n\n", strrchr (__FILE__, '\\'), __DATE__, __TIME__);

    OUT printf ("# Enter natural number, which you want to decompose (type it and press ENTER)\n");
    while (scanf ("%ld", &n) != 1) {printf ("\n# Incorrect input, try again"); return -1;}

    int success = Contains_3_Sqr (n, &sqr1, &sqr2, &sqr3);

    ASSERT (success == 1 || success == -1);

    switch (success)
    {
        case -1:
            printf ("\n-1");
            OUT printf ("\n# The number %ld can't be decomposed", n);
            break;

        case 1:
            printf ("\n%ld %ld %ld", sqr1, sqr2, sqr3);
            OUT printf ("\nThe number %ld can be decomposed:\n"
                        "%ld = %ld + %ld + %ld = %.0lf^2 + %.0lf^2 + %.0lf^2",\
                         n, n, sqr1, sqr2, sqr3, sqrt (sqr1), sqrt (sqr2), sqrt (sqr3));
            break;
    }

return 0;
}

int Contains_3_Sqr (long num, long* sqr1, long* sqr2, long* sqr3)
{
    ASSERT (sqr1);
    ASSERT (sqr2);
    ASSERT (sqr3);

    ASSERT (sqr1 != sqr2);
    ASSERT (sqr1 != sqr3);
    ASSERT (sqr2 != sqr3);

    int possibility = -1;

    long a = 0;
    long sqrtnum = floor (sqrt (num)) + 1;

    for (a = 0; a <= sqrtnum; ++a)
    {
        long sqr_a = a * a;
        long n1 = num - sqr_a;
        long sqrt_n1 = floor (sqrt (n1)) + 1;
        long b = 0;

        while (b <= sqrt_n1)
        {
            long sqr_b = b * b;

            if (num == sqr_a + sqr_b +
                (floor (sqrt (n1 - sqr_b))) * (floor (sqrt (n1 - sqr_b))))
            {
                *sqr1 = sqr_a;
                *sqr2 = sqr_b;
                *sqr3 = n1 - sqr_b;

                possibility = 1;

                break;
            }

            ++b;
        }
        if (possibility == 1) break;
    }

return possibility;
}
